<?php

namespace iBrand\Shop\Server\Http\Controllers;

use iBrand\Server\Http\Controllers\Controller;
use Carbon\Carbon;
use Cart;
use Dingo\Api\Http\Response;
use iBrand\Component\Address\Models\Address;
use iBrand\Component\Discount\Applicators\DiscountApplicator;
use iBrand\Component\Discount\Models\Coupon;
use iBrand\Component\Discount\Models\Discount;
use iBrand\Component\Discount\Services\DiscountService;
use iBrand\Component\Bundle\Repository\BundleRepository;
use iBrand\Component\Bundle\Applicator\BundleApplicator;
use iBrand\Component\Point\Repository\PointRepository;
use iBrand\Component\Point\Applicator\PointApplicator;
use iBrand\Component\Invoice\Model\InvoiceOrder;
use iBrand\Component\Invoice\Model\InvoiceUser;
use iBrand\Component\Order\Models\Comment;

use iBrand\Component\Order\Models\OrderItem;
use iBrand\Component\Order\Processor\OrderProcessor;
use iBrand\Component\Order\Repositories\Eloquent\OrderRepositoryEloquent;
use iBrand\Component\Order\Repositories\OrderRepository;
use iBrand\Component\Product\Models\Goods;
use iBrand\Component\Product\Models\Product;
use iBrand\Component\Product\Repositories\GoodsRepository;
use iBrand\Component\Product\Repositories\ProductRepository;
use iBrand\Component\Discount\Repositories\CouponRepository;
use iBrand\Component\Refund\Models\Refund;
use iBrand\Server\Transformers\CouponsTransformer;
use iBrand\Store\Backend\Model\SingleDiscountCondition;
use iBrand\TNF\Core\Models\Staff;
use Illuminate\Contracts\Auth\Access\Gate;
use Illuminate\Support\Collection;
use Illuminate\Events\Dispatcher;
//use Milon\Barcode\DNS1D;
use DNS1D;
use DB;
use iBrand\Component\Suit\Repositories\SuitRepository;
use iBrand\Component\Suit\Services\SuitService;
use  iBrand\Shoppingcart\Item;

use iBrand\Shop\Core\Repositories\UserShopRepository;
use iBrand\Shop\Core\Repositories\ClerkRepositoryEloquent;
use iBrand\Shop\Core\Repositories\ShopOrderRepository;
use iBrand\Component\User\Models\User;
use iBrand\Shop\Core\Models\ShopOrder;
use iBrand\Shop\Core\Models\Order;
use iBrand\Shop\Server\Service\OrderService;

class ShoppingController extends Controller
{
    private $goodsRepository;
    private $productRepository;
    private $discountService;
    private $orderRepository;
    private $discountApplicator;
    private $couponRepository;
    private $orderProcessor;
    private $bundleRepository;
    private $bundleApplicator;
    private $pointRepository;
    private $pointApplicator;
    private $event;
    private $suitRepository;
    private $suitService;
    private $userShopRepository;
    private $clerkRepository;
    private $ShopOrderRepository;
    private $orderService;

    public function __construct(GoodsRepository $goodsRepository
        , ProductRepository $productRepository
        , DiscountService $discountService
        , OrderRepository $orderRepository
        , CouponRepository $couponRepository
        , DiscountApplicator $discountApplicator
        , OrderProcessor $orderProcessor
        , BundleRepository $bundleRepository
        , BundleApplicator $bundleApplicator
        , PointRepository $pointRepository
        , PointApplicator $pointApplicator
        , Dispatcher $event
        , SuitRepository $suitRepository
        , SuitService $suitService
        , UserShopRepository $userShopRepository
        , ClerkRepositoryEloquent $clerkRepository
        , ShopOrderRepository $ShopOrderRepository
        , OrderService $orderService
    )
    {
        $this->goodsRepository = $goodsRepository;
        $this->productRepository = $productRepository;
        $this->discountService = $discountService;
        $this->orderRepository = $orderRepository;
        $this->discountApplicator = $discountApplicator;
        $this->couponRepository = $couponRepository;
        $this->orderProcessor = $orderProcessor;
        $this->bundleRepository = $bundleRepository;
        $this->bundleApplicator = $bundleApplicator;
        $this->pointRepository = $pointRepository;
        $this->pointApplicator = $pointApplicator;
        $this->event = $event;
        $this->suitRepository = $suitRepository;
        $this->suitService = $suitService;
        $this->userShopRepository = $userShopRepository;
        $this->clerkRepository = $clerkRepository;
        $this->ShopOrderRepository = $ShopOrderRepository;
        $this->orderService = $orderService;
    }

    public function checkout()
    {
        try {
            $clerk = auth('clerk')->user();
            /*if (!request('user_id') || !$user = $this->userShopRepository->getUserInfoByShopId($clerk->shop_id, request('user_id'))) {
                return $this->api([], false, 405, '会员不存在或会员非本门店会员');
            }*/
            if (!request('user_id') OR !$user = User::find(request('user_id'))) {
                return $this->api([], false, 405, '会员不存在');
            }

            //检查是否还有库存
            $cartItems = $this->getSelectedItemInCart();
            //|| empty(request('goods_id'))
            if ($this->checkStock($cartItems) === false) {

                return $this->api([], false, 500, '库存数量不够');
            }

            //生成订单
            $create = $this->orderService->createOrder($cartItems, request('user_id'), $clerk->shop_id);
            if (!$create['status']) {
                return $this->api([], $create['status'], $create['code'], $create['message']);
            }

            $order = $create['order'];
            //获取优惠信息
            $result = $this->orderService->getDiscount($order);
            $discountGroup = [];
            //$discountGroup = $this->discountService->getOrderDiscountGroup($order, new Collection($discounts), new Collection($result['coupons']));
            //积分计算
            $orderPoint = $this->orderService->getOrderPoint($order);
            //生成运费
            $order->payable_freight = 0;
            //获取默认地址
            $defaultAddress = Address::getDefaultAddress($user->user_id);

            return $this->api([
                'order' => $order,
                'discounts' => $result['discounts'],
                'coupons' => $result['coupons'],
                'address' => $defaultAddress,
                'in_source_discount_id' => $result['in_source_discount_id'],
                'orderPoint' => $orderPoint,
                'discountGroup' => $discountGroup,
                'invoice_status' => settings('invoice_status'),
            ], true);
        } catch (\Exception $exception) {
            return $this->api([], false, 400, $exception->getMessage());
        }
    }

    /**
     * confirm the order to be waiting to pay
     */
    public function confirm()
    {

        $clerk = auth('clerk')->user();
        $order_no = request('order_no');
        if (!$order_no || !$order = $this->orderRepository->getOrderByNo($order_no)) {
            return $this->response()->errorBadRequest('订单不存在');
        }

        $user = User::find($order->user_id);
        if ($user->cant('submit', $order)) {
            return $this->response()->errorForbidden('You have no right to submit this order.');
        }

        if ($note = request('note')) {
            $order->note = $note;
        }

        if ($order->type == Order::TYPE_SUIT AND request('point') AND !settings('point_suit_enabled')) {
            return $this->response()->errorForbidden('该套餐不能使用积分');
        }

        foreach ($order->getItems() as $item) {
            $model = $item->type;
            $model = new $model();
            $product = $model->find($item->item_id);

            if (!$product->getO2oProduct($clerk->shop_id)->getIsInSale($item->quantity)) {
                return $this->response()->errorForbidden('商品库存不够，请重新下单');
            }
        }

        try {

            DB::beginTransaction();
            if ($order->type == Order::TYPE_IN_SOURCE) {
                //员工内购处理
                //此订单消费额度
                if ($userRole = $user->roles->first()
                    AND $staff = Staff::where('mobile', $user->mobile)->first()
                    AND $staff->active_status == 1
                ) {

                    $channelDiscount = $this->discountService->getGoodsByRole($userRole->name);
                    $ruleGoods = $channelDiscount['spu'];
                    $percentageGroup = $channelDiscount['percentageGroup'];
                    $channelRole = true;

                    //3.get available discounts
                    $discounts = $channelDiscount['discounts'];

                    $amount = $order->total;

                    //计算本月剩余额度
                    $orderTable = 'el_order';
                    $orderItemTable = 'el_order_item';
                    $adjustmentTable = 'el_order_adjustment';
                    $amountUsed = Order::join($orderItemTable, $orderTable . '.id', '=', $orderItemTable . '.order_id')
                        ->whereRaw('DATE_ADD(curdate(),interval -day(curdate())+1 day) < ' . $orderTable . '.created_at')//本月
                        ->where($orderTable . '.type', '=', 2)
                        ->where($orderTable . '.user_id', '=', $user->id)
                        ->where($orderTable . '.pay_status', '=', 1)
                        ->sum($orderItemTable . '.units_total');
                    $amount = $amount / 100;
                    $amountUsed = $amountUsed / 100;

                    $refundTable = 'el_refund';

                    $refundAmount = Refund::join($orderTable, $orderTable . '.id', '=', $refundTable . '.order_id')
                        ->join($orderItemTable, $refundTable . '.order_item_id', '=', $orderItemTable . '.id')
                        ->whereRaw('DATE_ADD(curdate(),interval -day(curdate())+1 day) < ' . $orderTable . '.pay_time')//本月
                        ->where($refundTable . '.user_id', '=', $user->id)
                        ->where($refundTable . '.status', '=', Refund::STATUS_COMPLETE)
                        ->sum($orderItemTable . '.units_total');

                    $refundAmount = $refundAmount / 100;

                    $limit = settings('employee_discount_limit') ? settings('employee_discount_limit') : 0;
                    $limit = $limit - $amountUsed + $refundAmount;

                    //判断额度
                    if ($limit < $amount) {
                        return $this->response()->errorForbidden('员工内购额度不足，剩余额度：' . $limit . '，需要额度：' . $amount);
                    }

                    foreach ($discounts as $roleDiscount) {
                        $this->discountApplicator->apply($order, $roleDiscount);
                    }
                } else {
                    return $this->api([], false, 400, '内购折扣信息有误，请确认后重试');
                }
            } else {
                $discount = Discount::find(request('discount_id'));
                if (!empty($discount)) {
                    if ($this->discountService->checkDiscount($order, $discount)) {

                        /*$order->type = Order::TYPE_DISCOUNT;*/

                        $this->discountApplicator->apply($order, $discount);
                    } else {
                        return $this->response()->errorForbidden('折扣信息有误，请确认后重试');
                    }
                }

                if (empty($discount) OR $discount->exclusive != 1) {
                    //4. apply the available coupons
                    $coupon = Coupon::find(request('coupon_id'));
                    if (!empty($coupon)) {
                        if ($coupon->used_at != null) {
                            return $this->response()->errorForbidden('此优惠券已被使用');
                        }
                        if ($user->can('update', $coupon) AND $this->discountService->checkCoupon($order, $coupon)) {
                            $this->discountApplicator->apply($order, $coupon);
                        } else {
                            return $this->response()->errorForbidden('优惠券信息有误，请确认后重试');
                        }
                    }
                }
            }

            if ($order->type == Order::TYPE_POINT) {
                $userPoint = $this->pointRepository->getSumPointValid($user->id, 'default');
                if (request('point') > $userPoint) {
                    return $this->response()->errorForbidden('积分不够');
                }

                if (request('point') < $order->redeem_point) {
                    return $this->response()->errorForbidden('积分不够');
                }

                $this->pointRepository->create([
                    'user_id' => $order->user_id,
                    'action' => 'order_point',
                    'note' => '积分订单',
                    'value' => (-1) * request('point'),
                    'valid_time' => 0,
                    'item_type' => 'iBrand\Component\Order\Models\Order',
                    'item_id' => $order->id,
                ]);
                event('point.change', $user->id);
            } elseif (request('point') AND settings('point_enabled')) {
                $point = request('point');
                if ($this->pointRepository->checkUserPoint($order, $point)) {
                    $res = $this->pointApplicator->apply($order, $point);
                    if (!$res) {
                        return $this->response()->errorForbidden('积分处理出错');
                    }
                } else {
                    return $this->response()->errorForbidden('积分不足或不满足积分折扣规则');
                }

                //9. 创建积分使用信息
                if (request('point') AND settings('point_enabled')) {
                    $this->pointRepository->create([
                        'user_id' => $order->user_id,
                        'action' => 'order_discount',
                        'note' => '订单使用积分折扣',
                        'value' => (-1) * request('point'),
                        'valid_time' => 0,
                        'item_type' => 'iBrand\Component\Order\Models\Order',
                        'item_id' => $order->id,
                    ]);
                    event('point.change', $user->id);
                }
            }

            //5. 保存收获地址信息。
            if (request('address_id') == 0) {
                $order->address_name = '现场提货';
            } else {
                if ($address = Address::find(request('address_id'))) {
                    $order->accept_name = $address->accept_name;
                    $order->mobile = $address->mobile;
                    $order->address = $address->address;
                    $order->address_name = $address->address_name;
                }
            }

            //5. 保存订单状态
            $this->orderProcessor->process($order);

            //6. remove goods store.
            foreach ($order->getItems() as $item) {
                $model = $item->type;
                $model = new $model();
                $product = $model->find($item->item_id)->getO2oProduct($clerk->shop_id);
                $product->reduceStock($item->quantity);
                $product->increaseSales($item->quantity);
                $product->save();
            }

            //7. 保存发票信息
            if ($invoice_id = request('invoice_id') AND $invoice = InvoiceUser::find($invoice_id)) {
                InvoiceOrder::create([
                    'order_id' => $order->id,
                    'type' => $invoice->type,
                    'title' => $invoice->title,
                    'content' => $invoice->content,
                    'consignee_phone' => $invoice->consignee_phone,
                    'consignee_email' => $invoice->consignee_email,
                ]);
            }

            //8. 移除购物车中已下单的商品
            foreach ($order->getItems() as $orderItem) {
                if ($carItem = Cart::search(['name' => $orderItem->item_name])->first()) {
                    Cart::remove($carItem->rawId());
                }
            }

            if (!ShopOrder::where('order_id', $order->id)->first()) {
                $ratio = settings('o2o_clerk_royalty_ratio') ? settings('o2o_clerk_royalty_ratio') / 100 : 0;
                $o2o_clerk_royalty_order_amount = settings('o2o_clerk_royalty_order_amount') ? settings('o2o_clerk_royalty_order_amount') : 0;
                $o2o_clerk_royalty_order_amount_status = ($order->total * 100) - $o2o_clerk_royalty_order_amount;
                $value = 0;
                if ($order->total - $o2o_clerk_royalty_order_amount * 100 AND $ratio) {
                    $value = $order->total * $ratio;
                }
                ShopOrder::create(['order_id' => $order->id, 'clerk_id' => $clerk->id, 'shop_id' => $clerk->shop_id, 'value' => $value]);
            };

            DB::commit();

            return $this->api(['order' => $order], true);
        } catch (\Exception $exception) {
            DB::rollBack();
            \Log::info($exception->getMessage() . $exception->getTraceAsString());
            $this->response()->errorInternal($exception->getMessage());
        }
    }

    /**
     * cancel this order
     */
    public function cancel()
    {
        $clerk = auth('clerk')->user();
        $order_no = request('order_no');
        if (!$order_no || !$order = $this->orderRepository->getOrderByNo($order_no)) {
            return $this->response()->errorBadRequest('订单不存在');
        }

        if (!$this->ShopOrderRepository->getOrderInfoByClerk($clerk, $order->id)) {
            return $this->api([], false, 400, '无权操作此订单');
        };

        $user = User::find($order->user_id);

        if ($user->cant('cancel', $order)) {
            return $this->response()->errorForbidden('You have no right to cancel this order.');
        }

        $this->orderService->cancel($order);

        return $this->api([], true, 200, '订单取消成功');
    }

    /**
     * received this order
     */
    public function received()
    {
        $clerk = auth('clerk')->user();
        try {

            DB::beginTransaction();

            $order_no = request('order_no');
            if (!$order_no || !$order = $this->orderRepository->getOrderByNo($order_no)) {
                return $this->response()->errorBadRequest('订单不存在');
            }

            if (!$this->ShopOrderRepository->getOrderInfoByClerk($clerk, $order->id)) {
                return $this->api([], false, 400, '无权操作此订单');
            };

            $user = User::find($order->user_id);

            if ($user->cant('received', $order)) {
                return $this->response()->errorForbidden('You have no right to received this order.');
            }

            $this->orderProcessor->received($order);

            DB::commit();

            return $this->api([], true, 200, '确认收货操作成功');
        } catch (\Exception $exception) {
            DB::rollBack();
            \Log::info($exception->getMessage() . $exception->getTraceAsString());
            $this->response()->errorInternal($exception->getMessage());
        }
    }

    public function delete()
    {

        $clerk = auth('clerk')->user();
        $order_no = request('order_no');
        if (!$order_no || !$order = $this->orderRepository->getOrderByNo($order_no)) {
            return $this->response()->errorBadRequest('订单不存在');
        }

        if (!$this->ShopOrderRepository->getOrderInfoByClerk($clerk, $order->id)) {
            return $this->api([], false, 400, '无权操作此订单');
        };

        $user = User::find($order->user_id);

        if ($user->cant('delete', $order)) {
            return $this->response()->errorForbidden('You have no right to delete this order.');
        }

        $this->orderProcessor->delete($order);

        return $this->api([], true, 200, '删除无效订单成功');
    }

    private function getSelectedItemInCart()
    {
        //获取购物车中选中的商品数据

        $ids = request('cart_ids');

        if (!$ids || count($ids) == 0)
            return false;


        $cartItems = new Collection();

        foreach ($ids as $cartId) {
            $cartItems->put($cartId, Cart::get($cartId));
        }
        return $cartItems;
    }

    private function checkStock($cartItems)
    {
        $flag = true;
        if (count($cartItems) == 0) {
            return false;
        }

        $clerk = auth('clerk')->user();
        foreach ($cartItems as $key => $item) {
            $checkStore = $item->model->getO2oProduct($clerk->shop_id)->getIsInSale($item->qty);
            if (is_null($item->model) || !$checkStore) {
                Cart::update($key, ['message' => '库存数量不够', 'status' => 'onhand']);
                $flag = false;
            }
        }
        return $flag;
    }

    public function extraInfo($user_id)
    {
        $clerk = auth('clerk')->user();
        if (!$user = $this->userShopRepository->getUserInfoByShopId($clerk->shop_id, $user_id)) {
            return $this->api([], false, 405, '会员不存在或会员非本门店会员');
        }

        $point = $this->pointRepository->getSumPointValid($user_id, 'default');
        $pointToMoney = settings('point_proportion') ? settings('point_proportion') : 0;
        $pointLimit = settings('point_order_limit') ? settings('point_order_limit') : 1;

        return $this->api([
            'userPoint' => $point,
            'pointToMoney' => $pointToMoney / 1,
            'pointLimit' => $pointLimit / 100,
        ]);
    }

}